﻿using System;
using Notoric.Commanding.CommandBase;

namespace Notoric.ViewModel.Elements.CWNotation
{
    /// <summary>
    /// Adapts a <see cref="Model.Elements.CWNotation.Clef"/> instance to a Windows Presentation Foundation view.
    /// </summary>
    public class Clef : CoreSymbol
    {
        #region Constructors

        /// <summary>
        /// Creates a new <see cref="Clef"/> instance.
        /// </summary>
        /// <param name="owner">
        /// <para>
        /// Type: <see cref="Staff"/>
        /// </para>
        /// <para>
        /// The element that directly owns this element.
        /// </para>
        /// </param>
        /// <param name="adaptedElement">
        /// <para>
        /// Type: <see cref="Model.Elements.CWNotation.Clef"/>
        /// </para>
        /// <para>
        /// The adapted model element instance.
        /// </para>
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="adaptedElement"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="NullReferenceException">
        /// <paramref name="owner"/> is <see langword="null"/>.
        /// The values of the <see cref="ViewModelElement.UndoStack"/> and <see cref="ViewModelElement.RedoStack"/> properties
        /// are passed directly to the base class (<see cref="ViewModelElement"/>) constructor. Thus, there is not
        /// an occasion to react with a more appropriate exception.
        /// </exception>
        public Clef(Staff owner, Model.Elements.CWNotation.Clef adaptedElement)
            : base(owner, adaptedElement)
        {
			
        }

        #endregion

        #region ViewModelElement Members

        /// <inheritdoc/>
        public override string ElementNameKey
        {
            get { return elementNameKey; }
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Creates an undoable command for setting the <see cref="Type"/> of the clef.
        /// </summary>
        /// <param name="type">
        /// <para>
        /// Type: <see cref="ClefType"/>
        /// </para>
        /// <para>
        /// The new type of the clef.
        /// </para>
        /// </param>
        /// <returns>
        /// <para>
        /// Type: <see cref="UndoableCommandBase"/>
        /// </para>
        /// <para>
        /// The created command ready for execution.
        /// </para>
        /// </returns>
        public UndoableCommandBase CreateSetTypeCommand(ClefType type)
        {
            var modelType = (Model.Elements.CWNotation.ClefType)Enum.Parse(typeof(Model.Elements.CWNotation.ClefType), type.ToString());

            return new SetterCommand<Model.Elements.CWNotation.ClefType>(this, "Type", modelType, UndoStack, RedoStack);
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets or sets the type of the clef.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="ClefType"/>
        /// </para>
        /// <para>
        /// The type of the clef.
        /// </para>
        /// </value>
        public ClefType Type
        {
            get
            {
                var modelType = GetPropertyValue<Model.Elements.CWNotation.ClefType>("Type");

                return (ClefType)Enum.Parse(typeof(ClefType), modelType.ToString());
            }
            set
            {
                if (UnsavedChanges.ContainsKey("Type"))
                {
                    var cmd = (SetterCommand<Model.Elements.CWNotation.ClefType>)UnsavedChanges["Type"];
                    cmd.Value = (Model.Elements.CWNotation.ClefType)Enum.Parse(typeof(Model.Elements.CWNotation.ClefType), value.ToString());
                }
                else
                    UnsavedChanges["Type"] = CreateSetTypeCommand(value);

                RaisePropertyChanged("Type");
            }
        }

        #endregion

        #region Private Fields

        /// <summary>
        /// Holds a user-friendly name of this element.
        /// </summary>
        private const string elementNameKey = "ViewModel.ElementNames.Clef";
        
        #endregion
    }

    /// <summary>
    /// Describes the type of a clef.
    /// </summary>
    /// <seealso cref="Clef"/>
    public enum ClefType
    {
        /// <summary>
        /// G-clef assigns the G4 note to the line on which it is placed.
        /// </summary>
        G,
        /// <summary>
        /// C-clef assigns the middle C note to the line on which it is placed.
        /// </summary>
        C,
        /// <summary>
        /// F-clef assigns the F3 note to the line on which it is placed.
        /// </summary>
        F
    }
}
